package main;

import gui.MainGUI;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.InputMismatchException;
import java.util.Vector;
import java.util.logging.Level;

import logic.Parser;

import utility.Editor;
import utility.EditorInterface;
import utility.InputEmptyException;
import utility.InputInvalidException;
import utility.InvalidOperationException;
import utility.LoggerFMN;
import utility.Task;
import utility.UserInput;


public class Control implements ControlInterface {

	private static final String STANDARDISED_DATE_FORMAT = "dd/MM/yy";
	private EditorInterface ef;
	private MainGUI gui;
	private Calendar calendar;
	private int panelIndex;
	private static Control onlyOne = null;

	private void startUp() throws ParseException, IOException {
		MainGUI abc = new MainGUI();
		gui = abc;
		Editor temp = new Editor();
		ef = temp;
		calendar = Calendar.getInstance();
		panelIndex = 0;
		LoggerFMN.setUp();
	}

	private Control() throws ParseException, IOException {
	}

	public static Control getInstance() throws ParseException, IOException {
		if (onlyOne == null) {
			onlyOne = new Control();
			onlyOne.startUp();
			onlyOne.setUpGUI();
		}
		return onlyOne;
	}

	private void setUpGUI() throws ParseException, IOException {
		ef.initEditor();
		updateGUI();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see utility.ControlInterface#processInput(java.lang.String)
	 */
	@Override
	public void processInput(String input) throws ParseException, IOException {
		UserInput ui = null;
		try {
			ui = Parser.validate(input);
		} catch (InputEmptyException iee) {
			if (!iee.getMessage().isEmpty()) {
				gui.lightRed(iee.getMessage());
			}
			return;
		} catch (InputMismatchException | ParseException | InputInvalidException e) {
			gui.lightRed(e.getMessage());
			return;
		}
		ui.panelNumber = panelIndex;
		try {
			executeInput(ui);
		} catch (InvalidOperationException e) {
			gui.lightRed(e.getMessage());
			return;
		}
		String message = getFeedBack(ui);
		gui.lightGreen(message);
		updateGUI();
	}

	private void updateGUI() throws IOException, ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat(STANDARDISED_DATE_FORMAT);
		String todayDate = sdf.format(calendar.getTime());
		ef.update(todayDate);
		updateMyTasksPanel(ef.retrieveTasks());
		updateCompletedTasksPanel(ef.retrieveCompletedTasks());
		updateOverdueTasksPanel(ef.retrievePastTasks());
		updateGUIToday(ef.getTodayTasks(todayDate));
	}

	public void executeInput(UserInput ui) throws InvalidOperationException {
		try {
			switch (ui.command) {

			case "exit":
				System.exit(0);
				break;
			case "add":
				ef.addTask(ui);
				break;
			case "del":
			case "delete":
				ef.deleteTask(ui);
				break;
			case "dis":
			case "display":	
				ef.displayTasks(ui);
				break;
			case "edi":
			case "edit":
				ef.editTask(ui);
				break;
			case "und":
			case "undo":
				ef.undoPrevious();
				break;
			case "red":
			case "redo":
				ef.redo();
				break;
			case "src":
			case "search":
				ef.searchWord(ui);
				break;
			case "done":
				ef.setDone(ui);
				break;
			case "undone":
				ef.setUndone(ui);
				break;
			}
		} catch (IOException e) {
			LoggerFMN.LOGGER.log(Level.SEVERE, "File access is denied.");
			assert false;
		} catch (ParseException pe) {
			LoggerFMN.LOGGER.log(Level.SEVERE, "Contract between Parser and Editor has been violated.");
			assert false;
		} 
	}

	private String getFeedBack(UserInput ui) {
		switch (ui.command) {
		case "add":
			return "Task added successfully.";
		case "del":
		case "delete":
			return "Task deleted successfully.";
		case "edi":
		case "edit":
			return "Task edited successfully.";
		case "done":
			return "Task done successfully.";
		case "undone":
			return "Task undone successfully.";
		}
		return "";
	}

	private void updateOverdueTasksPanel(Vector<Task> retrievePastTasks) {
		String[][] tasks = modifyForGUIDisplay(retrievePastTasks);
		gui.updateOverdueTasksPanel(tasks);
	}

	private void updateCompletedTasksPanel(Vector<Task> retrieveCompletedTasks) {
		String[][] tasks = modifyForGUIDisplay(retrieveCompletedTasks);
		gui.updateCompletedTasksPanel(tasks);
	}

	public void updateGUIToday(Vector<Task> todayTasks) {
		String[][] today = modifyForGUIToday(todayTasks);
		gui.updateTodayEventPanel(today);
	}

	public void updateMyTasksPanel(Vector<Task> retrieveTasks) {
		String[][] table = modifyForGUIDisplay(retrieveTasks);
		gui.updateMyTasksPanel(table);
	}

	private String[][] modifyForGUIToday(Vector<Task> todayTasks) {
		String[][] output = new String[todayTasks.size()][3];
		int i = 0;
		for (Task t : todayTasks) {
			output[i][0] = t.startTime;
			output[i][1] = t.endTime;
			output[i++][2] = t.task;
		}
		return output;
	}

	private String[][] modifyForGUIDisplay(Vector<Task> retrieveTasks) {
		int i = 0;
		String[][] output = new String[retrieveTasks.size()][6];
		for (Task t : retrieveTasks) {
			output[i][0] = String.valueOf(i + 1);
			output[i][1] = t.startDate;
			output[i][2] = t.startTime;
			output[i][3] = t.endDate;
			output[i][4] = t.endTime;
			output[i][5] = t.task;
			i++;

		}
		return output;
	}

	public void changeCurrentPanel(int panelIndex) {
		this.panelIndex = panelIndex;
		System.out.print(this.panelIndex);
	}
}
